index.md (3322B)
1 --- 2 title: Remove Specific Files from Old Git Commit 3 author: Yohanes Bandung Bondowoso 4 description: "Ever accidentally committed <code>node_modules</code>? 5 Or want to remove files from a commit 15 before <code>HEAD</code>? 6 I did. I'd like to share the solution for you." 7 tags: 8 - git #git 9 - tutorial #tutorial 10 date: 2020-05-16T13:01:19+0700 11 image: 12 src: 1.png 13 ID: 1589608880 14 --- 15 16 tldr; [Skip to solution ยป](#how-tos) 17 18 Last week, I encountered a merge conflict while trying to sync my git working branch to latest remote `master`. Merge conflicts is not a serious problem to me, I am used to resolving conflicts. But the conflict that I encountered is from an auto generated typings file from `Apollo Codegen`[^1]. 19 20 `Apollo Codegen` file is `Flow` or `TypeScript` typings for the schema and queries in project that uses GraphQL. The generated file often has >10k lines of code. Trying to resolve conflict in that file will make the text editor unresponsive (even with Vim!). 21 22 So I aborted the sync master (`git rebase --abort`), then attempt to remove the changes for the auto-generated codegen file [using lazygit](#lazygit-way). Afterwards, I do sync remote `master` branch and the conflict don't happen. Last thing I do is regenerate the codegen file before posting a Pull Request. 23 24 ## How-Tos 25 26 Back to the post's main topic, to remove specific file using plain old shell command. 27 28 First, checkout to **temporary branch** with the afore mentioned commit as `HEAD` using the commit's hash: 29 30 ```bash 31 git checkout <commit-hash> 32 ``` 33 34 Then do a **soft reset** to uncommit with all files in staged status: 35 36 ```bash 37 git reset --soft HEAD^ 38 ``` 39 40 Make the desired file(s) unstaged using **reset** command, and then commit with `-c ORIG_HEAD` flag to use the previous commit message. The `--no-edit` flag is optional. 41 42 ```bash 43 git reset <path/to/file> 44 ``` 45 ```bash 46 git commit -c ORIG_HEAD --no-edit 47 ``` 48 49 Discard the changes of the file you want to remove from unstaged area: 50 51 ```bash 52 git checkout -- . 53 ``` 54 55 Last, `rebase` this **temporary branch** to your branch, from the commit of `<commit-hash>`. 56 57 ```bash 58 git rebase --onto HEAD <commit-hash> <destination-branch-name> 59 ``` 60 61 If you do this for already merged Pull Request, you need to `push <remote> <branch> --force`. Mind you, doing this will be inconvenient for other people working on same project. 62 63 ## Lazygit Way 64 65 As I mentioned above, I use [lazygit](https://github.com/jesseduffield/lazygit). The process is more straight forward. For the following example, I accidentally committed build file, far before I `.gitignore`d `build/` folder. What I do is: 66 67  68 69  70 71  72 73  74 75 Do this way if you want to install lazygit before doing your intention. 76 77 `lazygit` way is easier. I also use [tig](https://github.com/jonas/tig) as a TUI for `git`, but I don't know the command to do the steps wit `tig`. 78 79 [^1]: Here is `Apollo Codegen` [Github](https://github.com/apollographql/apollo-tooling#apollo-clientcodegen-output) page. As a frontend engineer, I consider `codegen` as breakthrough because I can easily type the endpoint's return value.